import json
from typing import Optional, List, Union

import numpy as np
import pandas as pd


def get_silent_chunks(silent_timestamp, interval=2):
    if not silent_timestamp:  # 如果列表为空，直接返回空列表
        return []

    sublists = [[]]  # 初始化子列表容器，包含一个空子列表
    for i in range(len(silent_timestamp)):
        # 如果子列表为空或者当前数字与子列表最后一个数字连续
        if not sublists[-1] or 0 < silent_timestamp[i] - sublists[-1][-1] < interval:
            # 将当前数字添加到子列表末尾
            sublists[-1].append(silent_timestamp[i])
        else:
            # 当前数字与子列表最后一个数字不连续，开始一个新的子列表
            sublists.append([silent_timestamp[i]])

    return sublists


def extract_silent_times(silent_times, interval=2, end_time=86400):
    last_silent_time = 0
    ranges = []
    for silent_time in silent_times:
        # silent_time = silent_time.strip("\n")
        # silent_time_int = timestamp2int(silent_time)
        if silent_time - last_silent_time < interval:
            last_silent_time = silent_time
            continue
        else:
            ranges.append((last_silent_time, silent_time))
            # if silent_time_int - last_silent_time > 1800:
            #     print(silent_time_int, last_silent_time)
            last_silent_time = silent_time

    if end_time - last_silent_time > interval:
        ranges.append((last_silent_time, end_time))

    return ranges


def make_valid_ranges(silent_points: Union[List, np.ndarray], interval=2, duration=86400):
    if isinstance(silent_points, str):
        with open(silent_points, "r") as f:
            silent_timestamp = json.loads(f.read())
    elif isinstance(silent_points, np.ndarray):
        silent_timestamp = silent_points.tolist()
    else:
        silent_timestamp = silent_points
    silent_chunks = get_silent_chunks(silent_timestamp, interval)
    silent_timestamp = [t[-1] for t in silent_chunks]
    ranges = extract_silent_times(silent_timestamp, end_time=duration)
    return ranges


def merge_ranges(ranges, chunk_size, insert_points=[], interval=5):
    duration = 0
    new_ranges = []
    merge_ranges = ranges[0]
    for i in range(1, len(ranges)):
        cur_range_ = ranges[i]
        pre_range_ = ranges[i - 1]
        duration += (cur_range_[1] - pre_range_[0])
        if duration > chunk_size:
            new_ranges.append(merge_ranges)
            duration = 0
            merge_ranges = ranges[i]
        else:
            merge_ranges = (merge_ranges[0], cur_range_[1])
    if len(merge_ranges) > 0:
        new_ranges.append(merge_ranges)
        merge_points = np.unique(new_ranges)
        new_points = merge_points.tolist() + np.unique(insert_points).tolist()
        new_points = sorted(new_points)
        new_ranges = make_valid_ranges(new_points, interval)
    return new_ranges


def seconds_to_hms(seconds_num: int):
    """
    输入秒数 转换为 时分秒输出
    param: seconds_num integer 666
    return: hms str 00:00:00a
    """
    m, s = divmod(seconds_num, 60)
    h, m = divmod(m, 60)
    hms = "%02d:%02d:%02d" % (h, m, s)
    return hms

def find_most_inclusive_ranges(ranges, target_time):
    """
    找出完全包含给定时间段的范围最多的ID。

    :param ranges: 一个包含(start, end)元组的列表，表示一系列时间范围
    :param target_time: 一个(start, end)元组，表示感兴趣的时间段
    :return: 包含最多给定时间段的范围ID，如果有多个，则返回任意一个
    """

    # 确保target_time被包含在范围内
    def is_inclusive(range_, target):
        return range_[0] >= target[0] and range_[1] <= target[1]

    # 计数每个范围是否包含目标时间
    matches = [is_inclusive(range_, target_time) for range_ in ranges]

    # 获取匹配的范围ID及其数量
    matched_ids = [i for i, match in enumerate(matches) if match]

    # 如果没有匹配的范围，返回None
    if not matched_ids:
        return None, None

    # 返回匹配范围的第一个ID（假设我们要的是任意一个）
    return matched_ids[0], matched_ids[-1]

def merge_intervals(intervals: Union[np.ndarray, list], miss_interval=0):
    if isinstance(intervals, list):
        intervals = np.array(intervals)
    intervals = np.sort(intervals, axis=0)
    if len(intervals) == 1:
        return intervals

    start_id = 0
    while start_id < intervals.shape[0] - 1:
        next_id = start_id + 1
        pair = intervals[[start_id, next_id]]
        if pair[:, 0].max() - pair[:, 1].min() < miss_interval:
            new_interval = np.array([pair.min(), pair.max()])
            # if 84296 in pair:
            #     print(pair, new_interval)
            intervals[start_id] = new_interval
            intervals = np.delete(intervals, next_id, axis=0)
        else:
            start_id += 1

    return intervals


def merge_overlapping_intervals(intervals):
    if isinstance(intervals, np.ndarray):
        intervals = intervals.tolist()
    if not intervals or not intervals[0]:
        return []

    # 对区间按照起始位置排序
    intervals.sort(key=lambda x: x[0])

    merged = []
    for interval in intervals:
        if not merged or merged[-1][1] < interval[0]:
            merged.append(interval)
        else:
            merged[-1] = [merged[-1][0], max(merged[-1][1], interval[1])]

    return merged


def find_uncovered_intervals(total_range, sub_ranges):
    # 将子区间按起始位置排序
    sorted_sub_ranges = sorted(sub_ranges, key=lambda x: x[0])

    # 初始化已覆盖的最大位置
    max_covered_end = total_range[0]

    # 初始化结果列表，用于存储未覆盖的区间
    uncovered_intervals = []

    # 遍历每个子区间
    for start, end in sorted_sub_ranges:
        # 如果当前子区间的起始位置大于已覆盖的最大位置，说明中间有未覆盖的部分
        if start > max_covered_end:
            # 添加未覆盖的部分到结果列表

            uncovered_intervals.append((max_covered_end, start))
            if end >= total_range[1]:
                return uncovered_intervals

            else:
                # 更新已覆盖的最大位置
                max_covered_end = end
        else:
            max_covered_end = end

    # 检查最后一个子区间结束位置之后是否有未覆盖的部分
    if max_covered_end < total_range[1]:
        uncovered_intervals.append((max_covered_end, total_range[1]))

    return uncovered_intervals